Skip to content

Improved testing for "max intervals" (Interval[null, null]) and "unknown intervals" (Interval(null, null)) - #116

Merged
brynrhodes merged 2 commits into
mainfrom
br-106-interval-null-null
Sep 19, 2026
Merged

brynrhodes merged 2 commits into
mainfrom
br-106-interval-null-null

Conversation

@brynrhodes

Copy link
Copy Markdown
Member

Fixed #106

… "unknown intervals" (Interval(null, null))
@bryantaustin13

bryantaustin13 commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

The following tests have unmatched actual vs expected results. If that is as it should be, due to clinical_quality_language errors, then I am willing to approve. I am willing to enter issues into the cql repo.

If Interval[null, null] actually means Interval[minimum value, maximum vale] then that explains many of the expected values.

TestMaxIntervalEndsFalse returns null, but expected is false
Interval[1, 10] ends Interval[null, null]
https://cql.hl7.org/09-b-cqlreference.html#ends
should be false supported by the Ends, Start, and End operator definitions in above link
TestIntegerInMaxIntervalTrue returns false, but expected is true
5 in Interval[null, null]
https://cql.hl7.org/09-b-cqlreference.html#in
5 >= null → treated as true (closed null boundary)
5 <= null → treated as true (closed null boundary)
TestIntegerInUnknownIntervalNull returns false, but expected is null
5 in Interval(null, null)
https://cql.hl7.org/09-b-cqlreference.html#in
5 > null
5 < null
treated as null
TestMaxIntervalOverlapsTrue returns null, but expected is true
TestMaxIntervalOverlapsBeforeTrue returns null, but expected is true
TestMaxIntervalOverlapsAfterTrue returns null, but expected is true
TestPointFromMaxIntervalError has no expected output
TestMaxIntervalStartsFalse returns null, but expected is false
TestUnionMaxInterval returns null, expected is Interval[null, null]

@brynrhodes

Copy link
Copy Markdown
Member Author

Correct, I believe the expected outcomes here are correct, and if an engine isn't getting these results, it needs to be corrected.

Comment thread tests/cql/CqlIntervalOperatorsTest.xml Outdated

@bryantaustin13 bryantaustin13 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Evaluated and approved

@richfirely richfirely left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by Firely during Connectathon meeting 9/19/2026.

@alexzautke

Copy link
Copy Markdown
Contributor

This is causing issues in cqframework/dqm-content-qicore-2025#58

@brynrhodes
brynrhodes merged commit f591d9e into main Sep 19, 2026
2 checks passed
@brynrhodes
brynrhodes deleted the br-106-interval-null-null branch September 19, 2026 14:51
@dehall

dehall commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Apologies for not noticing this before this was merged, but I think this might need more discussion.
Looking at this test for example:

<test name="TestMaxIntervalOverlapsTrue" version="1.0">
<capability code="interval-operators"/>
<expression>Interval[null, null] overlaps Interval[1, 10]</expression>
<output>true</output>

Interval[null, null] overlaps Interval[1, 10] should return true. That's only true if the type of the first operand can be inferred as Interval<Integer>. If the type of the first operand is Interval<Any> then the start and end operators just return null, and so the result of the overlaps should be null. So it's really a question of what types need to be inferred here.

The function signature for overlaps is overlaps _precision_ (left Interval<T>, right Interval<T>) Boolean so how is T, the common type, determined? In cases like this where there's a choice between Integer and Any, is the choice made based on the first operand, or the widest compatible choice, or the narrowest compatible choice? I couldn't find an answer in the spec.

Related issue on the translator: cqframework/clinical_quality_language#1856

@alexzautke

Copy link
Copy Markdown
Contributor

@dehall I don't think start/end would actually return null if T = Any.

  • Start of a closed-null low bound returns "the minimum value of the point type of the interval", and End likewise returns the maximum.
  • For Any, that would be MinValue(Any), and the spec says "for any other type, attempting to invoke MinValue results in an error" (MinValue).

So if T = Any, I'd expect an error (or the expression to be rejected) rather than null. As far as I can tell, null is only the right answer for the open form Interval(null, null), where the bounds are unknown.

@alexzautke

Copy link
Copy Markdown
Contributor

Also I would argue that Integer is the only real possibility here. Interval<Any> isn't a valid interval type, no? The Interval selector says "an interval must be defined using a point type that supports comparison, as well as Successor and Predecessor operations, and Minimum and Maximum Value operations." That's not supported by Any. So T = Any isn't a real candidate for overlaps(Interval<T>, Interval<T>), which leaves T = Integer.

@dehall

dehall commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

From that same link for Start:

If the low boundary is null and the interval point type is unknown, a choice of types, or Any, then the result cannot be determined and this operator returns null.

But this sentence is new in CQL 2.0.0, not in 1.5.3: https://cql.hl7.org/N1A/04-logicalspecification.html#start

I agree that Integer is the only useful choice in this scenario, but if we have the expression Interval[null, null] without any additional context, what type is it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove incorrect interval with null boundaries test

5 participants